Commit ae3ea197 authored by Leigh B Stoller's avatar Leigh B Stoller

Add speaksfor to GeniSA/MA/StdSA modules, and add/fix things to

support the genidesktop.
parent 9064171a
...@@ -54,6 +54,7 @@ use File::Temp qw(tempfile); ...@@ -54,6 +54,7 @@ use File::Temp qw(tempfile);
use Date::Parse; use Date::Parse;
use POSIX qw(strftime); use POSIX qw(strftime);
use Time::Local; use Time::Local;
use Carp qw(cluck carp);
use overload ('""' => 'Stringify'); use overload ('""' => 'Stringify');
# Exported variables # Exported variables
...@@ -412,6 +413,11 @@ sub CreateFromSigned($$;$) ...@@ -412,6 +413,11 @@ sub CreateFromSigned($$;$)
$nosig = 0 $nosig = 0
if (!defined($nosig)); if (!defined($nosig));
if (!defined($string)) {
$msg = "No string";
goto bad;
}
# First verify the credential # First verify the credential
if (! $nosig) { if (! $nosig) {
my ($fh, $filename) = tempfile(UNLINK => 0); my ($fh, $filename) = tempfile(UNLINK => 0);
...@@ -675,6 +681,7 @@ sub CreateFromSigned($$;$) ...@@ -675,6 +681,7 @@ sub CreateFromSigned($$;$)
$msg = "Internal error creating credential object"; $msg = "Internal error creating credential object";
} }
print STDERR "$msg\n"; print STDERR "$msg\n";
cluck("$msg");
$CreateFromSignedError = $msg; $CreateFromSignedError = $msg;
return undef; return undef;
} }
...@@ -1130,6 +1137,27 @@ sub CheckCredential($;$$) ...@@ -1130,6 +1137,27 @@ sub CheckCredential($;$$)
return $credential; return $credential;
} }
#
# Load a certificate from a file. This creates an object, but does
# not store it in the DB.
#
sub LoadFromFile($$)
{
my ($class, $filename) = @_;
my $contents = "";
if (! open(CRED, $filename)) {
print STDERR "Could not open $filename: $!\n";
return undef;
}
while (<CRED>) {
$contents .= $_;
}
close(CRED);
return GeniCredential->CreateFromSigned($contents);
}
######################################################################## ########################################################################
# ABAC version of a credential. This a total hack job, will need to # ABAC version of a credential. This a total hack job, will need to
# be flushed and redone later. # be flushed and redone later.
......
...@@ -84,18 +84,25 @@ sub LookupPublic($) ...@@ -84,18 +84,25 @@ sub LookupPublic($)
sub LookupPrivate($$) sub LookupPrivate($$)
{ {
my ($credential_args, $options) = @_; my ($credential_args, $options) = @_;
my ($credential) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args)); my ($credential,$speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential return $credential
if (GeniResponse::IsResponse($credential)); if (GeniResponse::IsResponse($credential));
return GeniResponse->MalformedArgsResponse("Missing self credential")
if (!defined($credential));
# #
# We need to enforce Emulab permissions here, since the credential # We need to enforce Emulab permissions here, since the credential
# allows anyone with a credential for this registry to lookup anyone # allows anyone with a credential for this registry to lookup anyone
# else. Good feature of the Geni API. # else. Good feature of the Geni API.
# #
my $this_user = GeniUser->Lookup($ENV{'GENIURN'}, 1); my $this_user =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($this_user)) { if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Permission denied. Only local users are allowed to make private lookups."); "Permission denied. Only local users are allowed ".
"to make private lookups.");
} }
$credential->HasPrivilege( "authority" ) or $credential->HasPrivilege( "authority" ) or
...@@ -119,19 +126,25 @@ sub LookupIdentifying($$) ...@@ -119,19 +126,25 @@ sub LookupIdentifying($$)
{ {
my ($credential_args, $options) = @_; my ($credential_args, $options) = @_;
my ($credential) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args)); my ($credential,$speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential return $credential
if (GeniResponse::IsResponse($credential)); if (GeniResponse::IsResponse($credential));
return GeniResponse->MalformedArgsResponse("Missing self credential")
if (!defined($credential));
# #
# We need to enforce Emulab permissions here, since the credential # We need to enforce Emulab permissions here, since the credential
# allows anyone with a credential for this registry to lookup anyone # allows anyone with a credential for this registry to lookup anyone
# else. Good feature of the Geni API. # else. Good feature of the Geni API.
# #
my $this_user = GeniUser->Lookup($ENV{'GENIURN'}, 1); my $this_user =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($this_user)) { if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Permission denied. Only local users are allowed to make identifying lookups."); "Permission denied. Only local users are allowed ".
"to make identifying lookups.");
} }
$credential->HasPrivilege( "authority" ) or $credential->HasPrivilege( "authority" ) or
...@@ -171,7 +184,19 @@ sub GetCredentials($$$) ...@@ -171,7 +184,19 @@ sub GetCredentials($$$)
{ {
my ($member_urn, $credential_args, $options) = @_; my ($member_urn, $credential_args, $options) = @_;
my $credential = GeniSA::GetCredential({ "urn" => $member_urn }); #
# Need to know if only a speaksfor is provided.
#
my ($credential,$speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
my $args = { "urn" => $member_urn };
if (defined($speaksfor)) {
$args->{"credential"} = $speaksfor->asString();
}
$credential = GeniSA::GetCredential($args);
return $credential return $credential
if (GeniResponse::IsError($credential)); if (GeniResponse::IsError($credential));
...@@ -207,7 +232,44 @@ sub UpdateKey($$$$) ...@@ -207,7 +232,44 @@ sub UpdateKey($$$$)
sub LookupKeys($$) sub LookupKeys($$)
{ {
my ($credentials, $options) = @_; my ($credential_args, $options) = @_;
return GeniResponse->Create(GENIRESPONSE_NOT_IMPLEMENTED); my ($credential,$speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
return GeniResponse->MalformedArgsResponse("Missing self credential")
if (0 && !defined($credential));
#
# We need to enforce Emulab permissions here, since the credential
# allows anyone with a credential for this registry to lookup anyone
# else. Good feature of the Geni API.
#
my $this_user =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Permission denied.");
}
defined($credential) &&
($credential->HasPrivilege( "authority" ) or
$credential->HasPrivilege( "resolve" ) or
return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
"Insufficient privilege" ));
my @keys;
if ($this_user->GetKeyBundle(\@keys) != 0) {
print STDERR "Could not get keys for $this_user\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my @list = ();
foreach my $key (@keys) {
push(@list, {"KEY_PUBLIC" => $key->{'key'} });
}
my $blob = { $this_user->urn() => \@list };
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
} }
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2008-2013 University of Utah and the Flux Group. # Copyright (c) 2008-2014 University of Utah and the Flux Group.
# #
# {{{GENIPUBLIC-LICENSE # {{{GENIPUBLIC-LICENSE
# #
...@@ -52,6 +52,7 @@ use GeniCredential; ...@@ -52,6 +52,7 @@ use GeniCredential;
use GeniCertificate; use GeniCertificate;
use GeniAuthority; use GeniAuthority;
use GeniHRN; use GeniHRN;
use GeniStd;
use English; use English;
use XML::Simple; use XML::Simple;
use Data::Dumper; use Data::Dumper;
...@@ -91,32 +92,53 @@ sub GetCredential($) ...@@ -91,32 +92,53 @@ sub GetCredential($)
my ($argref) = @_; my ($argref) = @_;
my $urn = $argref->{'urn'}; my $urn = $argref->{'urn'};
my $cred = $argref->{'credential'}; my $cred = $argref->{'credential'};
my $creds = $argref->{'credentials'};
my $geniuser;
if (0 && $MAINSITE) { if (0 && $MAINSITE) {
print STDERR "Debugging getslicecred()\n"; print STDERR "Debugging getslicecred()\n";
} }
# #
# No credential, then return a generic credential giving user permission # This credential is for access to this SA.
# to do other things.
# #
if (!defined($cred)) { my $authority = GeniAuthority->Lookup($ENV{'MYURN'});
my $geniuser = GeniUser->Lookup($ENV{'GENIURN'}, 1); if (!defined($authority)) {
if (!defined($geniuser)) { print STDERR
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, "Could not find local authority object for $ENV{'MYURN'}\n";
undef, "Who are you?"); return GeniResponse->Create(GENIRESPONSE_ERROR);
} }
#
# If we got *only* a speaks-for credential, then a tool is asking for
# a self-cred on behalf of a user.
#
if (defined($cred)) {
my ($credential,$speaksfor) =
GeniStd::CheckCredentials([$cred], $authority);
return $credential
if (GeniResponse::IsResponse($credential));
if (defined($speaksfor)) {
$geniuser = GeniUser->Lookup($speaksfor->target_urn(), 1);
if (!defined($geniuser)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN,
undef, "Who are you speaking for?");
}
# Asking for a self cred for the target user.
goto selfcred;
}
}
elsif (!(defined($cred) || defined($creds))) {
# #
# This credential is for access to this SA. # No cred, caller wants a self credential.
# #
my $authority = GeniAuthority->Lookup($ENV{'MYURN'}); $geniuser = GeniUser->Lookup($ENV{'GENIURN'}, 1);
if (!defined($authority)) { if (!defined($geniuser)) {
print STDERR return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Could not find local authority object for $ENV{'MYURN'}\n"; "Who are you?");
return GeniResponse->Create(GENIRESPONSE_ERROR);
} }
selfcred:
if( !CheckMembership( $geniuser ) ) { if( !CheckMembership( $geniuser ) ) {
return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, return GeniResponse->Create( GENIRESPONSE_FORBIDDEN,
undef, "No privilege at this " . undef, "No privilege at this " .
...@@ -160,7 +182,13 @@ sub GetCredential($) ...@@ -160,7 +182,13 @@ sub GetCredential($)
print STDERR "Could not find local authority object\n"; print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR); return GeniResponse->Create(GENIRESPONSE_ERROR);
} }
my $credential = GeniCredential::CheckCredential($cred, $authority); my ($credential,$speaksfor);
if (defined($cred)) {
$credential = GeniCredential::CheckCredential($cred, $authority);
}
else {
($credential,$speaksfor) = GeniStd::CheckCredentials($creds, $authority);
}
return $credential return $credential
if (GeniResponse::IsResponse($credential)); if (GeniResponse::IsResponse($credential));
...@@ -169,14 +197,16 @@ sub GetCredential($) ...@@ -169,14 +197,16 @@ sub GetCredential($)
return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
"Insufficient privilege" ); "Insufficient privilege" );
my $this_user = GeniUser->Lookup($ENV{'GENIURN'}, 1);
if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN,
undef, "Who are you?");
}
my ($undef, $type, $id) = GeniHRN::Parse($urn); my ($undef, $type, $id) = GeniHRN::Parse($urn);
if( !CheckMembership( $this_user ) ) { $geniuser =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($geniuser)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Who are you? No local record");
}
if( !CheckMembership( $geniuser ) ) {
return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, return GeniResponse->Create( GENIRESPONSE_FORBIDDEN,
undef, "No privilege at this " . undef, "No privilege at this " .
"authority" ); "authority" );
...@@ -191,8 +221,8 @@ sub GetCredential($) ...@@ -191,8 +221,8 @@ sub GetCredential($)
# Bump the activity counter for the user. Lets us know in the # Bump the activity counter for the user. Lets us know in the
# main DB that a user is doing something useful. # main DB that a user is doing something useful.
# #
$this_user->BumpActivity() $geniuser->BumpActivity()
if ($this_user->IsLocal()); if ($geniuser->IsLocal());
my $slice = GeniSlice->Lookup($urn); my $slice = GeniSlice->Lookup($urn);
...@@ -202,8 +232,8 @@ sub GetCredential($) ...@@ -202,8 +232,8 @@ sub GetCredential($)
if ($slice->Lock() != 0) { if ($slice->Lock() != 0) {
return GeniResponse->BusyResponse("slice"); return GeniResponse->BusyResponse("slice");
} }
if ($slice->creator_urn() ne $this_user->urn() && if ($slice->creator_urn() ne $geniuser->urn() &&
!$slice->IsBound($this_user)) { !$slice->IsBound($geniuser)) {
$slice->UnLock(); $slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Not your slice!"); "Not your slice!");
...@@ -211,13 +241,13 @@ sub GetCredential($) ...@@ -211,13 +241,13 @@ sub GetCredential($)
# #
# Return a credential for the slice. # Return a credential for the slice.
# #
my $slice_credential = GeniCredential->Lookup($slice, $this_user); my $slice_credential = GeniCredential->Lookup($slice, $geniuser);
if (defined($slice_credential)) { if (defined($slice_credential)) {
# #
# Check for expiration and for changed certificate. # Check for expiration and for changed certificate.
# #
if ($slice_credential->IsExpired() || if ($slice_credential->IsExpired() ||
!$slice_credential->SameCerts($slice, $this_user)) { !$slice_credential->SameCerts($slice, $geniuser)) {
$slice_credential->Delete(); $slice_credential->Delete();
$slice_credential = undef; $slice_credential = undef;
} }
...@@ -225,7 +255,7 @@ sub GetCredential($) ...@@ -225,7 +255,7 @@ sub GetCredential($)
if (!defined($slice_credential)) { if (!defined($slice_credential)) {
$slice_credential = $slice_credential =
GeniCredential->CreateSigned($slice, GeniCredential->CreateSigned($slice,
$this_user, $geniuser,
$main::PROJECT ? $main::PROJECT ?
$authority->GetCertificate() : $authority->GetCertificate() :
$GeniCredential::LOCALSA_FLAG ); $GeniCredential::LOCALSA_FLAG );
...@@ -256,6 +286,7 @@ sub Resolve($) ...@@ -256,6 +286,7 @@ sub Resolve($)
my $urn = $argref->{'urn'}; my $urn = $argref->{'urn'};
my $cred = $argref->{'credential'}; my $cred = $argref->{'credential'};
my $type = $argref->{'type'}; my $type = $argref->{'type'};
my $creds = $argref->{'credentials'};
if (! (defined($hrn) || defined($urn))) { if (! (defined($hrn) || defined($urn))) {
return GeniResponse->MalformedArgsResponse(); return GeniResponse->MalformedArgsResponse();
...@@ -285,7 +316,7 @@ sub Resolve($) ...@@ -285,7 +316,7 @@ sub Resolve($)
(undef,$type,undef) = GeniHRN::Parse($urn); (undef,$type,undef) = GeniHRN::Parse($urn);
} }
$type = lc($type); $type = lc($type);
if (! defined($cred)) { if (! (defined($cred) || defined($creds))) {
return GeniResponse->MalformedArgsResponse(); return GeniResponse->MalformedArgsResponse();
} }
...@@ -294,7 +325,13 @@ sub Resolve($) ...@@ -294,7 +325,13 @@ sub Resolve($)
print STDERR "Could not find local authority object\n"; print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR); return GeniResponse->Create(GENIRESPONSE_ERROR);
} }
my $credential = GeniCredential::CheckCredential($cred, $authority); my ($credential, $speaksfor);
if (defined($cred)) {
$credential = GeniCredential::CheckCredential($cred, $authority);
}
else {
($credential,$speaksfor) = GeniStd::CheckCredentials($creds, $authority);
}
return $credential return $credential
if (GeniResponse::IsResponse($credential)); if (GeniResponse::IsResponse($credential));
...@@ -308,7 +345,9 @@ sub Resolve($) ...@@ -308,7 +345,9 @@ sub Resolve($)
# allows anyone with a credential for this registry to lookup anyone # allows anyone with a credential for this registry to lookup anyone
# else. Good feature of the Geni API. # else. Good feature of the Geni API.
# #
my $this_user = GeniUser->Lookup($ENV{'GENIURN'}, 1); my $this_user =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($this_user)) { if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Who are you? No local record"); "Who are you? No local record");
...@@ -410,11 +449,13 @@ sub Register($) ...@@ -410,11 +449,13 @@ sub Register($)
# (it's deduced automatically from the URN). # (it's deduced automatically from the URN).
my ($argref) = @_; my ($argref) = @_;
my $cred = $argref->{'credential'}; my $cred = $argref->{'credential'};
my $creds = $argref->{'credentials'};
my $type = $argref->{'type'}; my $type = $argref->{'type'};
my $hrn = $argref->{'hrn'}; my $hrn = $argref->{'hrn'};
my $urn = $argref->{'urn'}; my $urn = $argref->{'urn'};
if (! ((defined($hrn) || defined($urn)) && defined($cred))) { if (! ((defined($hrn) || defined($urn)) &&
(defined($cred) || defined($creds)))) {
return GeniResponse->MalformedArgsResponse(); return GeniResponse->MalformedArgsResponse();
} }
if (defined($urn)) { if (defined($urn)) {
...@@ -457,7 +498,13 @@ sub Register($) ...@@ -457,7 +498,13 @@ sub Register($)
print STDERR "Could not find local authority object\n"; print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR); return GeniResponse->Create(GENIRESPONSE_ERROR);
} }
my $credential = GeniCredential::CheckCredential($cred, $authority); my ($credential, $speaksfor);
if (defined($cred)) {
$credential = GeniCredential::CheckCredential($cred, $authority);
}
else {
($credential,$speaksfor) = GeniStd::CheckCredentials($creds, $authority);
}
return $credential return $credential
if (GeniResponse::IsResponse($credential)); if (GeniResponse::IsResponse($credential));
...@@ -471,7 +518,9 @@ sub Register($) ...@@ -471,7 +518,9 @@ sub Register($)
# allows anyone with a credential for this registry to lookup anyone # allows anyone with a credential for this registry to lookup anyone
# else. Good feature of the Geni API. # else. Good feature of the Geni API.
# #
my $this_user = GeniUser->Lookup($ENV{'GENIURN'}, 1); my $this_user =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($this_user)) { if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Who are you? No local record"); "Who are you? No local record");
...@@ -655,8 +704,10 @@ sub Remove($) ...@@ -655,8 +704,10 @@ sub Remove($)
my $urn = $argref->{'urn'}; my $urn = $argref->{'urn'};
my $cred = $argref->{'credential'}; my $cred = $argref->{'credential'};
my $type = $argref->{'type'}; my $type = $argref->{'type'};
my $creds= $argref->{'credentials'};
if (! ((defined($hrn) || defined($urn)) && defined($cred))) { if (! ((defined($hrn) || defined($urn)) &&
(defined($cred) || defined($creds)))) {
return GeniResponse->MalformedArgsResponse(); return GeniResponse->MalformedArgsResponse();
} }
if (defined($urn)) { if (defined($urn)) {
...@@ -688,7 +739,13 @@ sub Remove($) ...@@ -688,7 +739,13 @@ sub Remove($)
print STDERR "Could not find local authority object\n"; print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR); return GeniResponse->Create(GENIRESPONSE_ERROR);
} }
my $credential = GeniCredential::CheckCredential($cred, $authority); my ($credential, $speaksfor);
if (defined($cred)) {
$credential = GeniCredential::CheckCredential($cred, $authority);
}
else {
($credential,$speaksfor) = GeniStd::CheckCredentials($creds, $authority);
}
return $credential return $credential
if (GeniResponse::IsResponse($credential)); if (GeniResponse::IsResponse($credential));
...@@ -697,7 +754,9 @@ sub Remove($) ...@@ -697,7 +754,9 @@ sub Remove($)
return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
"Insufficient privilege" ); "Insufficient privilege" );
my $this_user = GeniUser->Lookup($ENV{'GENIURN'}, 1); my $this_user =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($this_user)) { if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Who are you? No local record"); "Who are you? No local record");
...@@ -770,10 +829,11 @@ sub GetKeys($) ...@@ -770,10 +829,11 @@ sub GetKeys($)
{ {
my ($argref) = @_; my ($argref) = @_;
my $cred = $argref->{'credential'}; my $cred = $argref->{'credential'};
my $creds = $argref->{'credentials'};
# Hidden option. Remove later. # Hidden option. Remove later.
my $version = $argref->{'version'} || 1; my $version = $argref->{'version'} || 1;
if (! defined($cred)) { if (! (defined($cred) || defined($creds))) {
return GeniResponse->MalformedArgsResponse(); return GeniResponse->MalformedArgsResponse();
} }