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);
use Date::Parse;
use POSIX qw(strftime);
use Time::Local;
use Carp qw(cluck carp);
use overload ('""' => 'Stringify');
# Exported variables
......@@ -412,6 +413,11 @@ sub CreateFromSigned($$;$)
$nosig = 0
if (!defined($nosig));
if (!defined($string)) {
$msg = "No string";
goto bad;
}
# First verify the credential
if (! $nosig) {
my ($fh, $filename) = tempfile(UNLINK => 0);
......@@ -675,6 +681,7 @@ sub CreateFromSigned($$;$)
$msg = "Internal error creating credential object";
}
print STDERR "$msg\n";
cluck("$msg");
$CreateFromSignedError = $msg;
return undef;
}
......@@ -1130,6 +1137,27 @@ sub CheckCredential($;$$)
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
# be flushed and redone later.
......
......@@ -84,18 +84,25 @@ sub LookupPublic($)
sub LookupPrivate($$)
{
my ($credential_args, $options) = @_;
my ($credential) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
my ($credential,$speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
return GeniResponse->MalformedArgsResponse("Missing self credential")
if (!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($ENV{'GENIURN'}, 1);
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. Only local users are allowed to make private lookups.");
"Permission denied. Only local users are allowed ".
"to make private lookups.");
}
$credential->HasPrivilege( "authority" ) or
......@@ -119,19 +126,25 @@ sub LookupIdentifying($$)
{
my ($credential_args, $options) = @_;
my ($credential) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
my ($credential,$speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
return GeniResponse->MalformedArgsResponse("Missing self credential")
if (!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($ENV{'GENIURN'}, 1);
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. Only local users are allowed to make identifying lookups.");
"Permission denied. Only local users are allowed ".
"to make identifying lookups.");
}
$credential->HasPrivilege( "authority" ) or
......@@ -171,7 +184,19 @@ sub GetCredentials($$$)
{
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
if (GeniResponse::IsError($credential));
......@@ -207,7 +232,44 @@ sub UpdateKey($$$$)
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);
}
This diff is collapsed.
#!/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
#
......@@ -47,6 +47,7 @@ use GeniRegistry;
use emutil;
use URI;
use Data::Dumper;
use Carp qw(cluck carp);
# Filter out any credentials of an uknown type leaving only geni_sfa
# version 2 and version 3 credentials in a list. Also invokes
......@@ -58,8 +59,11 @@ sub FilterCredentials
if (defined($credentials)) {
foreach my $cred (@{ $credentials }) {
if (ref($cred) eq "HASH" &&
$cred->{'geni_type'} eq "geni_sfa" &&
($cred->{'geni_version'} eq 2 || $cred->{'geni_version'} eq 3)) {
(($cred->{'geni_type'} eq "geni_sfa" &&
($cred->{'geni_version'} eq 2 ||
$cred->{'geni_version'} eq 3)) ||
($cred->{'geni_type'} eq "geni_abac" &&
($cred->{'geni_version'} eq 1)))) {
push(@{ $result }, $cred->{'geni_value'});
auto_add_sa($cred->{'geni_value'});
}
......@@ -76,7 +80,7 @@ sub auto_add_sa($)
my $signers = $cred->signer_certs();
return
if ($cred->type() eq "speaksfor");
if ($cred->type() eq "speaksfor" || $cred->type() eq "abac");
# The credential has been verified, so the signer derives from a
# trusted root.
......@@ -193,11 +197,18 @@ sub auto_add_sa($)
#
# Initial credential check.
#
sub CheckCredentials($)
sub CheckCredentials($;$)
{
my ($arg, $target_authority) = @_;
my ($speakee, $speaksfor);
my @rest = ();
my $error;
if (!defined($arg)) {
cluck("CheckCredentials: No credentials!");
$error = GeniResponse->Create(GENIRESPONSE_ERROR);
goto bad;
}
if (ref($_[0]) ne "ARRAY") {
$error = GeniResponse->MalformedArgsResponse("Credentials should be a ".
......@@ -206,14 +217,6 @@ sub CheckCredentials($)
}
else {
my @credential_strings = @{ $_[0] };
if (scalar(@credential_strings) == 1) {
#
# Must be a speaks-as credential.
#
$speakee = GeniCredential::CheckCredential($credential_strings[0]);
}
else {
#
# The only other case is that we get multiple credentials. One
# is the speaks-for credential and another one is the real
......@@ -242,7 +245,8 @@ sub CheckCredentials($)
# just the way I want it.
#
$speakee = shift(@credentials);
$speakee = GeniCredential::CheckCredential($speakee);
$speakee = GeniCredential::CheckCredential($speakee,
$target_authority);
if (GeniResponse::IsError($speakee)) {
$error = $speakee;
goto bad;
......@@ -253,7 +257,9 @@ sub CheckCredentials($)
# The rest of the credentials have to be valid too.
#
foreach my $credential (@rest) {
$credential = GeniCredential::CheckCredential($credential);
$credential =
GeniCredential::CheckCredential($credential,
$target_authority);
if (GeniResponse::IsError($credential)) {
$error = $credential;
goto bad;
......@@ -319,8 +325,9 @@ sub CheckCredentials($)
# by the user, so the owners must match.
#
foreach my $credential (@credentials) {
my $cred = GeniCredential::CheckCredential($credential,
undef, 1);
my $cred =
GeniCredential::CheckCredential($credential,
$target_authority, 1);
if (GeniResponse::IsError($cred)) {
$error = $cred;
goto bad;
......@@ -340,7 +347,7 @@ sub CheckCredentials($)
$speakee = shift(@credentials);
@rest = @credentials;
}
}
}
if (wantarray()) {
return ($speakee, $speaksfor, @rest);
......
......@@ -43,6 +43,8 @@ use vars qw(@ISA @EXPORT);
use GeniStd;
use GeniSA;
use GeniSlice;
use GeniUser;
use User;
use GeniResponse;
use GeniCredential;
use GeniRegistry;
......@@ -73,12 +75,9 @@ sub CreateSlice($$)
return GeniResponse->MalformedArgsResponse('Requires a list of credentials, an options field, and a SLICE_NAME in the options field');
}
my $credential = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
my $hrn = $options->{'fields'}->{'SLICE_NAME'};
my $args = {
"credential" => $credential->asString(),
"credentials" => GeniStd::FilterCredentials($credential_args),
"hrn" => $hrn,
"type" => "slice"
};
......@@ -156,9 +155,6 @@ sub LookupSlices()
sub UpdateSlice()
{
my ($slice_urn, $credential_args, $options) = @_;
my $credential = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
# TODO: Make sure that slice URN is the same as the credential URN
my $slice = GeniSlice->Lookup($slice_urn);
......@@ -168,8 +164,8 @@ sub UpdateSlice()
}
if (exists($options->{'fields'}->{'SLICE_EXPIRES'})) {
my $args = {
"credential" => $credential->asString(),
"expiration" => $options->{'fields'}->{'SLICE_EXPIRES'}
"credentials" => GeniStd::FilterCredentials($credential_args),
"expiration" => $options->{'fields'}->{'SLICE_EXPIRES'}
};
$response = GeniSA::RenewSlice($args);
}
......@@ -190,13 +186,9 @@ sub GetCredentials()
return GeniResponse->MalformedArgsResponse('Requires a slice urn, a list of credentials, and an options field');
}
my $user_credential = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $user_credential
if (GeniResponse::IsResponse($user_credential));
my $credential = GeniSA::GetCredential({
"urn" => $slice_urn,
"credential" => $user_credential });
"credentials" => GeniStd::FilterCredentials($credential_args) });
return $credential
if (GeniResponse::IsError($credential));
......@@ -219,8 +211,6 @@ sub ModifySliceMembership()
return GeniResponse->MalformedArgsResponse('Requires a slice urn, a list of credentials, and an options field');
}
my ($credential) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
my $adding = $options->{'members_to_add'};
my $removing = $options->{'members_to_remove'};
my $changing = $options ->{'members_to_change'};
......@@ -240,7 +230,7 @@ sub ModifySliceMembership()
}
my $params = {
"credential" => $credential->asString()
"credentials" => GeniStd::FilterCredentials($credential_args),
};
my $i = 0;
......@@ -266,8 +256,8 @@ sub LookupSliceMembers()
return GeniResponse->MalformedArgsResponse('Requires a slice urn, a list of credentials, and an options field');
}
my ($cred) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
my $credential = GeniCredential::CheckCredential($cred->asString());
my ($credential, $speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -276,7 +266,9 @@ sub LookupSliceMembers()
return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
"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)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Who are you? No local record");
......@@ -323,21 +315,22 @@ sub LookupSlicesForMember($$$)
return GeniResponse->MalformedArgsResponse('Requires a member urn, a list of credentials, and an options field');
}
my ($cred) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
my $credential = GeniCredential::CheckCredential($cred->asString());
my ($credential, $speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
if ($ENV{'GENIURN'} ne $member_urn) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"You are not allowed to lookup slices for other members");
}
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)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Who are you? No local record");
}
if ($this_user->urn() ne $member_urn) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"You are not allowed to lookup slices for other members");
}
my $result = [];
......@@ -345,9 +338,9 @@ sub LookupSlicesForMember($$$)
my @bound = GeniSlice->BoundToUser($this_user);
addSlicesToMemberList(\@created, $result)
if (defined(@created));
if (@created);
addSlicesToMemberList(\@bound, $result)
if (defined(@bound));
if (@bound);
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $result);
}
......@@ -374,7 +367,6 @@ sub CreateSliverInfo($$$$)
return GeniResponse->MalformedArgsResponse('Requires a list of credentials, and an options field');
}
my ($credential) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
if (! defined($options->{'SLIVER_INFO_SLICE_URN'}) ||
! defined($options->{'SLIVER_INFO_URN'}) ||
! defined($options->{'SLIVER_INFO_AGGREGATE_URN'}) ||
......@@ -384,7 +376,7 @@ sub CreateSliverInfo($$$$)
return GeniResponse->MalformedArgsResponse('Required option is missing. Make sure to include SLIVER_INFO_SLICE_URN, SLIVER_INFO_URN, SLIVER_INFO_AGGREGATE_URN, SLIVER_INFO_CREATOR_URN, CREATION, and EXPIRATION');
}
my $params = {
'credential' => $credential->asString(),
'credentials' => GeniStd::FilterCredentials($credential_args),
'slice_urn' => $options->{'SLIVER_INFO_SLICE_URN'},
'creator_urn' => $options->{'SLIVER_INFO_CREATOR_URN'},
'urn' => $options->{'SLIVER_INFO_URN'},
......@@ -412,9 +404,8 @@ sub DeleteSliverInfo()
return GeniResponse->MalformedArgsResponse('Requires a slice urn, an aggregate url, a list of credentials, and an options field');
}
my ($credential) = GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
my $params = {
'credential' => $credential->asString(),
'credentials' => GeniStd::FilterCredentials($credential_args),
'slice_urn' => $slice_urn
};
return GeniSA::UnRegisterSliver($params);
......@@ -423,8 +414,60 @@ sub DeleteSliverInfo()
sub LookupSliverInfo($$)
{
my ($credential_args, $options) = @_;
return GeniResponse->Create(GENIRESPONSE_NOT_IMPLEMENTED, undef,
"Lookup Sliver Info is not implemented");
if (! (defined($credential_args) && defined($options))) {
return
GeniResponse->MalformedArgsResponse('Requires a list of '.
'credentials, and an options field');
}
my ($credential, $speaksfor) =
GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
return $credential
if (GeniResponse::IsResponse($credential));
return GeniResponse->MalformedArgsResponse()
if (!defined($credential));
my $this_user =
GeniUser->Lookup((defined($speaksfor) ?
$speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Who are you? No local record");
}
my ($match, $filter) = GeniStd::GetMatchFilter($options);
if (! (defined($options->{'match'}) &&
defined($options->{'match'}->{'SLIVER_INFO_SLICE_URN'}))) {
return
GeniResponse->MalformedArgsResponse('Required match is missing: '.
'SLIVER_INFO_SLICE_URN');
}
my $slice = GeniSlice->Lookup($options->{'match'}{'SLIVER_INFO_SLICE_URN'});
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED)
if (!defined($slice));
if ($slice->Lock() != 0) {
return GeniResponse->BusyResponse("slice");
}
my @slivers = GeniSlice::ClientSliver->LookupBySlice($slice);
my $blob = {};
foreach my $sliver (@slivers) {
$blob->{$sliver->urn()} = {
'SLIVER_INFO_AGGREGATE_URN' => $sliver->manager_urn(),
'SLIVER_INFO_URN' => $sliver->urn(),
'SLIVER_INFO_SLICE_URN' => $slice->urn(),
'SLIVER_INFO_CREATION' => $sliver->created(),
'SLIVER_INFO_EXPIRATION' => $sliver->expires()
};
my $user = User->Lookup($sliver->creator_idx());
if (defined($user)) {
$user = GeniUser->CreateFromLocal($user);
}
if (defined($user)) {
$blob->{$sliver->urn()}->{'SLIVER_INFO_CREATOR_URN'} = $user->urn();
}
}
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
}
sub CreateProject()
......
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