Commit 56fef67b authored by Leigh B Stoller's avatar Leigh B Stoller

Assorted changes to make sure that the uid we grab from the user URN

is a valid Emulab user id (as for creating accounts on nodes) and for
inserting into the Emulab DB.

If the uid is not valid for us, make up a new one from a hash of the
certificate. This will give us a (typically) unique but always
consistent uid to use.

Also add the uid to the services/login section of the manifest so that
the client always knows what uid to use when logging in.
parent ef41d067
......@@ -382,15 +382,9 @@ sub GetTicketAux($$$$$$$)
# Create user from the certificate.
#
my $user = CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
if ($isupdate) {
print STDERR "Could not locate $user_urn for UpdateTicket\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"No user found for UpdateTicket");
}
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
#
# Create slice from the certificate.
#
......@@ -1932,9 +1926,9 @@ sub SliverWorkAux($$$$$$$)
# Create the user.
#
my $owner = CreateUserFromCertificate($owner_cert);
if (!defined($owner)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $owner
if (GeniResponse::IsResponse($owner));
if (defined($keys)) {
$response = CheckKeys($keys);
return $response
......@@ -3422,9 +3416,8 @@ sub GetSliverAux($)
"Insufficient privilege" );
my $user = CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
my $slice = GeniSlice->Lookup($credential->target_urn());
if (!defined($slice)) {
......@@ -3501,9 +3494,8 @@ sub BindToSlice($)
# Find or create the user.
#
my $user = CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
if (defined($keys)) {
my $response = CheckKeys($keys);
return $response
......@@ -3845,9 +3837,9 @@ sub SliverTicket($)
}
my $user = CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
my $aggregate = GeniAggregate->Lookup($credential->target_urn());
if (!defined($aggregate)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
......@@ -4035,10 +4027,8 @@ sub ListTickets($)
if (GeniResponse::IsResponse($credential));
my $user = CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"No such user found");
}
return $user
if (GeniResponse::IsResponse($user));
#
# A plain credential issued to a user lets that user get a list
......@@ -4148,21 +4138,30 @@ sub CreateUserFromCertificate($)
$certificate->Store();
$user = GeniUser->Lookup($certificate->urn());
if (!defined($user)) {
print STDERR "Could not reload user for $certificate\n";
return undef;
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Problem loading your certificate");
}
return $user;
}
#
# Check urn. Must be a "user" urn. The uid is checked in Create().
#
my (undef,$type,$uid) = GeniHRN::Parse($certificate->urn());
if (!defined($uid) || $type ne "user") {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Malformed user URN");
}
my $authority = CreateAuthorityFromRegistry($certificate);
return undef
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create authority object")
if (!defined($authority));
$user = GeniUser->Create($certificate, $authority);
if (!defined($user)) {
print STDERR "Could not create user from $certificate\n";
return undef;
}
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create user from your certificate")
if (!defined($user));
return $user;
}
......
......@@ -127,7 +127,8 @@ sub Resolve($)
my (undef,$callertype,$callerid) = GeniHRN::Parse($credential->owner_urn());
if ($callertype eq "user") {
my $user = GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (defined($user) && $user->IsLocal() && $user->admin()) {
if (!GeniResponse::IsResponse($user) &&
$user->IsLocal() && $user->admin()) {
$admin = 1;
}
}
......@@ -360,10 +361,9 @@ sub CreateSliver($)
}
my $user =
GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
if (GeniResponse::IsResponse($user)) {
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create user");
return $user;
}
if ($slice->ConvertPlaceholder($user) != 0) {
$slice->UnLock();
......@@ -502,9 +502,8 @@ sub DeleteSliver($)
# We need the user to sign the new ticket to.
#
my $user = GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
my $response = GeniCM::DeleteSliverAux($credential, $impotent, 1);
return $response
......@@ -1128,10 +1127,9 @@ sub GetTicket($)
}
my $user =
GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
if (GeniResponse::IsResponse($user)) {
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create user");
return $user;
}
if ($slice->ConvertPlaceholder($user) != 0) {
$slice->UnLock();
......@@ -1255,9 +1253,9 @@ sub UpdateTicket($)
# We need the user to sign the new ticket to.
#
my $user = GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
my $credential_objects = [];
foreach my $credstr (@$credentials) {
my $cred = CheckCredential($credstr);
......@@ -1329,9 +1327,9 @@ sub UpdateSliver($)
# Any user can update the sliver. The ticket is signed to that user.
#
my $user = GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
my $credential_objects = [];
foreach my $credstr (@$credentials) {
my $cred = CheckCredential($credstr);
......@@ -1426,9 +1424,9 @@ sub BindToSlice($)
# Find or create the user.
#
my $user = GeniCM::CreateUserFromCertificate($credential->owner_cert());
if (!defined($user)) {
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return $user
if (GeniResponse::IsResponse($user));
if (!$user->IsLocal() && defined($keys)) {
$user->Modify(undef, undef, $keys);
}
......
#!/usr/bin/perl -wT
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
package GeniCertificate;
......@@ -38,6 +38,7 @@ my $SIGNCRED = "$TB/sbin/signgenicred";
my $VERIFYCRED = "$TB/sbin/verifygenicred";
my $NFREE = "$TB/bin/nfree";
my $OPENSSL = "/usr/bin/openssl";
my $SHA1 = "/sbin/sha1";
my $MKCERT = "$TB/sbin/mksyscert";
# Cache of instances to avoid regenerating them.
......@@ -728,6 +729,23 @@ sub asText($)
return join("", @certlines);
}
sub sha1($)
{
my ($self) = @_;
my @result = $self->PipeTo(0, "$SHA1");
if (! @result) {
print STDERR "Could not convert $self to sha1 hash\n";
return undef;
}
my $hash = $result[0];
if ($hash =~ /^(\w*)$/) {
return $1;
}
print STDERR "Bad sha1 value for $self\n";
return undef;
}
#
# Load a CRL and store it.
#
......
......@@ -685,6 +685,7 @@ sub Create($$$$$$)
GeniXML::SetText("authentication", $login, "ssh-keys");
GeniXML::SetText("hostname", $login, $phostname);
GeniXML::SetText("port", $login, $sshdport);
GeniXML::SetText("username", $login, $user->uid());
my $sliver = GeniSliver->Create($slice, $user, $resource_uuid, "Node",
$resource_id, $hrn, $nickname, $rspec);
......
#!/usr/bin/perl -wT
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
package GeniUser;
......@@ -18,7 +18,7 @@ use GeniRegistry;
use GeniAuthority;
use GeniCertificate;
use GeniHRN;
use emutil qw(TBGetUniqueIndex);
use emutil;
use English;
use overload ('""' => 'Stringify');
use vars qw();
......@@ -70,15 +70,18 @@ sub Lookup($$;$)
if( GeniHRN::IsValid( $token ) ) {
$token = GeniHRN::Normalise( $token );
my $safe_token = DBQuoteSpecial($token);
my ($authority, $type, $id) = GeniHRN::Parse( $token );
return undef if $type ne "user";
if( GeniHRN::Authoritative( $token, "@OURDOMAIN@" ) ) {
my $safe_hrn = DBQuoteSpecial("${PGENIDOMAIN}.$id");
# A local name, so look only for local users...
$query_result =
DBQueryWarn("select idx from geni_users ".
"where hrn='${PGENIDOMAIN}.$id' " .
"where hrn=$safe_hrn " .
"and status='active'");
return undef
......@@ -101,7 +104,7 @@ sub Lookup($$;$)
$query_result = DBQueryWarn(
"SELECT geni_users.idx FROM geni_users, geni_certificates " .
"WHERE geni_users.uuid = geni_certificates.uuid AND " .
"geni_certificates.urn = '$token';" );
"geni_certificates.urn = $safe_token;" );
return undef unless $query_result and $query_result->numrows;
}
($idx) = $query_result->fetchrow_array();
......@@ -267,6 +270,18 @@ sub CheckConflict($$)
return $query_result->numrows;
}
#
# Check to see if a uid is valid (and okay for a password file).
#
sub ValidUserID($$)
{
my ($class, $uid) = @_;
return TBcheck_dbslot($uid, "users", "uid",
TBDB_CHECKDBSLOT_WARN()|
TBDB_CHECKDBSLOT_ERROR());
}
#
# Class function to create new Geni user in the DB and return object.
#
......@@ -304,13 +319,32 @@ sub Create($$$$;$)
push(@insert_data, "sa_uuid='$sa_uuid'");
#
# uid comes from last component of the hrn.
# uid comes from urn, but only if its valid for Emulab.
#
my ($uid) = ($certificate->hrn() =~ /^.*\.(\w*)$/);
if (!defined($uid)) {
print STDERR "HRN is not dotted: " . $certificate->hrn() . "\n";
my (undef,$type,$uid) = GeniHRN::Parse($certificate->urn());
if (!defined($uid) || $type ne "user") {
print STDERR "URN is not well formed: " . $certificate->urn() . "\n";
return undef;
}
if (! GeniUser->ValidUserID($uid)) {
print STDERR
"UID is not valid for Emulab: " . $certificate->urn() . "\n";
#
# Create something reasonable and consistent.
# It gets returned in the manifest.
#
my $hash = $certificate->sha1();
return undef
if (!defined($hash));
$hash = substr($hash, 0, 7);
if (!$hash || GeniUser->ValidUserID("u${hash}")) {
print STDERR "Cannot form a uid from certificate\n".
$certificate->cert() . "\n";
return undef;
}
$uid = lc("u${hash}");
print STDERR "Using $uid instead\n";
}
#
# This comes from either an info record or the cert.
......@@ -442,6 +476,11 @@ sub Delete($)
my $idx = $self->idx();
my $uuid = $self->uuid();
my $emulab_user = User::NonLocal->Lookup($uuid);
if (defined($emulab_user)) {
$emulab_user->Delete();
}
DBQueryWarn("delete from geni_bindings where user_uuid='$uuid'")
or return -1;
DBQueryWarn("delete from geni_userkeys where uuid='$uuid'")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment