GeniMA.pm.in 8.03 KB
Newer Older
Jonathon Duerig's avatar
Jonathon Duerig committed
1 2
#!/usr/bin/perl -wT
#
Leigh B Stoller's avatar
Leigh B Stoller committed
3
# Copyright (c) 2008-2014 University of Utah and the Flux Group.
Jonathon Duerig's avatar
Jonathon Duerig committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
# 
# {{{GENIPUBLIC-LICENSE
# 
# GENI Public License
# 
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
# 
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
# 
# }}}
#
package GeniMA;

#
33
# Shim for implementing standard GENI MA interface.
Jonathon Duerig's avatar
Jonathon Duerig committed
34 35 36 37 38 39 40 41
#
use strict;
use Exporter;
use vars qw(@ISA @EXPORT);

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

42
use GeniStd;
Jonathon Duerig's avatar
Jonathon Duerig committed
43 44 45 46 47
use GeniSA;
use GeniResponse;
use GeniCredential;
use GeniRegistry;
use emutil;
48 49 50
use Data::Dumper;

my $coder = Frontier::RPC2->new('use_objects' => 1);
Jonathon Duerig's avatar
Jonathon Duerig committed
51 52 53 54

sub GetVersion()
{
    my $blob = {
55 56 57
	"VERSION" => $coder->string("0.2"),
	"CREDENTIAL_TYPES" => ["SFA"], #=> [$coder->string("3")]],
	"SERVICES" => ["MEMBER"]
Jonathon Duerig's avatar
Jonathon Duerig committed
58 59 60 61 62 63
    };
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
}

sub LookupPublic($)
{
64
    my ($credential_args, $options) = @_;
65 66

    my ($match, $filter) = GeniStd::GetMatchFilter($options);
Jonathon Duerig's avatar
Jonathon Duerig committed
67 68

    my $members = {};
69 70 71 72 73 74 75 76 77 78
    foreach my $key (@{ $match }) {
	my $geniuser = GeniUser->Lookup($key, 1);
	if (defined($geniuser)) {
	    my $completeblob = {
		"MEMBER_URN"      => $geniuser->urn(),
		"MEMBER_UID"      => $geniuser->uid(),
		"MEMBER_USERNAME" => $geniuser->hrn()
	    };
	    my $blob = GeniStd::FilterFields($completeblob, $filter);
	    $members->{$geniuser->urn()} = $blob;
Jonathon Duerig's avatar
Jonathon Duerig committed
79 80 81 82 83 84 85 86
	}
    }
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, $members);
}

sub LookupPrivate($$)
{
    my ($credential_args, $options) = @_;
87 88
    my ($credential,$speaksfor) =
	GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
Jonathon Duerig's avatar
Jonathon Duerig committed
89 90
    return $credential
	if (GeniResponse::IsResponse($credential));
91 92 93
    return GeniResponse->MalformedArgsResponse("Missing self credential")
	if (!defined($credential));
   
94 95 96 97 98
    #
    # 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.
    #
99 100 101
    my $this_user =
	GeniUser->Lookup((defined($speaksfor) ?
			  $speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
102 103
    if (!defined($this_user)) {
	return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
104 105
			    "Permission denied. Only local users are allowed ".
				    "to make private lookups.");
106 107
    }

Jonathon Duerig's avatar
Jonathon Duerig committed
108 109 110 111
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "resolve" ) or
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );
112
    my ($match, $filter) = GeniStd::GetMatchFilter($options);
Jonathon Duerig's avatar
Jonathon Duerig committed
113 114

    my $members = {};
115 116 117 118 119
    foreach my $key (@{ $match }) {
	my $geniuser = GeniUser->Lookup($key, 1);
	if (defined($geniuser)) {
	    my $blob = {};
	    $members->{$geniuser->urn()} = $blob;
Jonathon Duerig's avatar
Jonathon Duerig committed
120 121 122 123 124 125 126 127 128
	}
    }
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, $members);
}

sub LookupIdentifying($$)
{
    my ($credential_args, $options) = @_;

129 130
    my ($credential,$speaksfor) =
	GeniStd::CheckCredentials(GeniStd::FilterCredentials($credential_args));
Jonathon Duerig's avatar
Jonathon Duerig committed
131 132
    return $credential
	if (GeniResponse::IsResponse($credential));
133 134
    return GeniResponse->MalformedArgsResponse("Missing self credential")
	if (!defined($credential));
Jonathon Duerig's avatar
Jonathon Duerig committed
135
   
136 137 138 139 140
    #
    # 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.
    #
141 142 143
    my $this_user =
	GeniUser->Lookup((defined($speaksfor) ?
			  $speaksfor->target_urn() : $ENV{'GENIURN'}), 1);
144 145
    if (!defined($this_user)) {
	return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
146 147
			    "Permission denied. Only local users are allowed ".
				    "to make identifying lookups.");
148 149
    }

Jonathon Duerig's avatar
Jonathon Duerig committed
150 151 152 153 154
    $credential->HasPrivilege( "authority" ) or
	$credential->HasPrivilege( "resolve" ) or
	return GeniResponse->Create( GENIRESPONSE_FORBIDDEN, undef,
				     "Insufficient privilege" );

155
    my ($match, $filter) = GeniStd::GetMatchFilter($options);
Jonathon Duerig's avatar
Jonathon Duerig committed
156 157

    my $members = {};
158 159 160 161 162 163 164 165 166 167 168 169 170
    foreach my $key (@{ $match }) {
	my $geniuser = GeniUser->Lookup($key, 1);
	if (defined($geniuser)) {
	    my @namelist = split(/ /, $geniuser->name());
	    my $lastname = pop(@namelist);
	    my $firstname = join(" ", @namelist);
	    my $completeblob = {
		"MEMBER_FIRSTNAME" => $firstname,
		"MEMBER_LASTNAME"  => $lastname,
		"MEMBER_EMAIL"     => $geniuser->email()
	    };
	    my $blob = GeniStd::FilterFields($completeblob, $filter);
	    $members->{$geniuser->urn()} = $blob;
Jonathon Duerig's avatar
Jonathon Duerig committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	}
    }
    return GeniResponse->Create(GENIRESPONSE_SUCCESS, $members);
}

sub UpdateMember($$$)
{
    my ($member_urn, $credential_args, $options) = @_;
    return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
				"Update Member is Unimplemented");
}

sub GetCredentials($$$)
{
    my ($member_urn, $credential_args, $options) = @_;

187 188 189 190 191 192 193 194 195 196 197 198 199
    #
    # 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);
Jonathon Duerig's avatar
Jonathon Duerig committed
200
    return $credential
201
	if (GeniResponse::IsError($credential));
Jonathon Duerig's avatar
Jonathon Duerig committed
202 203

    my $blob = {
204
	"geni_type" => "geni_sfa",
205
	"geni_version" => $coder->string("3"),
206
	"geni_value" => $credential->{"value"}
Jonathon Duerig's avatar
Jonathon Duerig committed
207 208 209 210
    };

    return GeniResponse->Create(GENIRESPONSE_SUCCESS, [$blob]);
}
211 212 213 214

sub CreateKey($$$)
{
    my ($member_urn, $credential_args, $options) = @_;
Leigh B Stoller's avatar
Leigh B Stoller committed
215 216

    return GeniResponse->Create(GENIRESPONSE_NOT_IMPLEMENTED);
217 218 219 220 221
}

sub DeleteKey($$$$)
{
    my ($member_urn, $key_id, $credentials, $options) = @_;
Leigh B Stoller's avatar
Leigh B Stoller committed
222 223

    return GeniResponse->Create(GENIRESPONSE_NOT_IMPLEMENTED);
224 225 226 227 228
}

sub UpdateKey($$$$)
{
    my ($member_urn, $key_id, $credentials, $options) = @_;
Leigh B Stoller's avatar
Leigh B Stoller committed
229 230

    return GeniResponse->Create(GENIRESPONSE_NOT_IMPLEMENTED);
231 232 233 234
}

sub LookupKeys($$)
{
235
    my ($credential_args, $options) = @_;
Leigh B Stoller's avatar
Leigh B Stoller committed
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    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);
275
}