Commit c50139c6 authored by Leigh Stoller's avatar Leigh Stoller

Add delegation support to run on boss to make it easier for an admin

to delegate a credential to a user. Say you want to delegate a CH
credential to a local user so they can lookup things:

boss> getchcredential | delegatecredential 'urn:publicid:IDN+emulab.net+user+XXX' resolve:0

This will spit out a delegated credential. Save that in a file and
give to the user. The user then sends that along as the credential
argument.
parent c4c8823f
......@@ -763,9 +763,10 @@ sub Delegate($$)
print STDERR "Could not delegate $self to $owner\n";
return undef;
}
foreach my $cap (keys(%{ $self->capabilities() })) {
$credential->AddCapability($cap, 0);
}
#
# The new credential has no privs; the caller has to fill
# them for this credential to be useful.
#
$credential->{'parent_cred'} = $self;
$credential->{'valid_until'} = $self->{'valid_until'};
return $credential;
......@@ -783,6 +784,11 @@ sub Store($)
return 0
if (defined($self->idx()));
if (defined($self->{'parent_cred'})) {
print STDERR "Not allowed to store delegted credential: $self\n";
return -1;
}
# Every credential store gets a new unique index.
my $idx = TBGetUniqueIndex('next_ticket', 1);
......
......@@ -18,8 +18,8 @@ PSBIN_STUFF = register_resources expire_daemon gencrl postcrl \
gencrlbundle shutdownslice remauthority listusage \
update reregister cleanupticket listhistory \
register_sliver sa_daemon genadmincredential \
genclrcredentials genallow_extcred advt-merge.py \
reservevlans delgeniuser
getchcredential genallow_extcred advt-merge.py \
reservevlans delgeniuser delegatecredential
ifeq ($(ISMAINSITE),1)
PSBIN_STUFF += ch_daemon
......
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use English;
use Getopt::Std;
#
# This script can be used to delegate a credential to a local user.
# Acts as the SA, but use -c to act as the CM. The credential is
# specified as a text file on the command line, or on stdin. The output
# is written to the file or stdout. The permissions to delegate are
# specified as pairs in the form 'perm:delegate" where 'perm' is
# something like "resolve" and 'delegate' is a boolean that says if
# that permission can be further delegated. You must supply at least
# one permission (can be special tag 'all' to grant all perms).
#
# For example:
#
# boss> getchcredential | delegatecredential urn:stoller resolve:0 list:1
#
# Note that I shortened the URN for brevity.
#
sub usage()
{
print STDERR "Usage: $0 [-c] [-i input_file] [-o output_file] <user-urn> ";
print STDERR "[permission,delegate ...]\n";
exit(-1);
}
my $optlist = "ci:o:";
my $ascm = 0;
my $infile;
my $outfile;
# Configure ...
my $TB = "@prefix@";
my $SACERT = "$TB/etc/genisa.pem";
my $CMCERT = "$TB/etc/genicm.pem";
# Do this early so that we talk to the right DB.
use vars qw($GENI_DBNAME);
BEGIN { $GENI_DBNAME = "geni"; }
use lib '@prefix@/lib';
use GeniCredential;
use GeniCertificate;
use GeniAuthority;
use GeniHRN;
use GeniResponse;
use GeniUser;
use GeniRegistry;
sub fatal($)
{
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"i"})) {
$infile = 1;
}
if (defined($options{"o"})) {
$outfile = 1;
}
if (defined($options{"c"})) {
$ascm = 1;
}
usage()
if (@ARGV < 2);
my $user_urn = shift();
#
# Must be an emulab user.
#
if (! (GeniHRN::IsValid($user_urn))) {
fatal("Malformed user urn");
}
my $geniuser = GeniUser->Lookup($user_urn, 1);
if (!defined($geniuser)) {
fatal("No such user in the DB");
}
#
# Load the cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile(($ascm ? $CMCERT : $SACERT));
if (!defined($certificate)) {
fatal("Could not load certificate\n");
}
Genixmlrpc->SetContext(Genixmlrpc->Context($certificate));
#
# Load the input credential.
#
my $credstring = "";
if ($infile) {
open(IN, $infile)
or fatal("Could not open $infile");
while (<IN>) {
$credstring .= $_;
}
}
else {
while (<STDIN>) {
$credstring .= $_;
}
}
my $credential = GeniCredential->CreateFromSigned($credstring);
if (!defined($credential)) {
fatal("Could not load credential\n");
}
my $delegate = $credential->Delegate($geniuser);
#
# Add the perms
#
foreach my $arg (@ARGV) {
if ($arg =~ /^(\w*):(\d)$/) {
$delegate->AddCapability($1, $2);
}
else {
fatal("Bad permission: $arg");
}
}
if ($delegate->Sign(($ascm ? $GeniCredential::LOCALCM_FLAG :
$GeniCredential::LOCALSA_FLAG)) != 0) {
fatal("Could not sign delegated credential");
}
if ($outfile) {
open(OUT, ">$outfile")
or fatal("Could not open $outfile");
print OUT $delegate->asString();
close(OUT);
}
else {
print $delegate->asString();
}
exit(0);
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use lib '@prefix@/lib';
# Do this early so that we talk to the right DB.
use vars qw($GENI_DBNAME $GENI_ISCLRHOUSE);
BEGIN { $GENI_DBNAME = "geni-ch"; $GENI_ISCLRHOUSE = 1; }
use GeniCredential;
use GeniCertificate;
use GeniAuthority;
use GeniHRN;
use GeniResponse;
use GeniUser;
# This script can be used to issue a credential to a user with specified
# clearinghouse as target with only Resolve privilege. It means he can only
# List and Resolve on the clearinghouse.
# ./genclrcredentials.pl <user-urn> <clearinghouse-urn>
sub CreateSpecialCredential
{
my $owner_urn = shift;
my $target_ch_urn = shift;
#
# Must be an emulab user who is talking to us.
# If any of the URN specified is invalid do no accept.
if (! (GeniHRN::IsValid($owner_urn) &&
GeniHRN::IsValid($target_ch_urn))) {
return GeniResponse->MalformedArgsResponse();
}
my $geniuser = GeniUser->Lookup($owner_urn, 1);
if (!defined($geniuser)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN,
undef, "Who are you?");
}
my $authority = GeniAuthority->Lookup($target_ch_urn);
if (!defined($authority)) {
print STDERR "Could not find local authority object for".
"$target_ch_urn\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $signer = $GeniCredential::LOCALMA_FLAG;
my $credential = GeniCredential->Create($authority, $geniuser);
if (!defined($credential)) {
print "Could not create credential for $authority, $geniuser\n";
return undef;
}
$credential->AddCapability("resolve",1);
if ($credential->Sign($signer) != 0) {
$credential->Delete();
print "Could not sign credential for $authority, $geniuser\n";
return undef;
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS,
$credential->asString());
}
my $numArgs = $#ARGV + 1;
if($numArgs !=2) {
print "Please specify <user-urn> <ch-urn> as command line arguments\n\n";
}else{
my $val = CreateSpecialCredential @ARGV;
#print $val->{"output"};
#print $val->{"code"};
print $val->{"value"};
}
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use lib '@prefix@/lib';
# Do this early so that we talk to the right DB.
use vars qw($GENI_DBNAME);
BEGIN { $GENI_DBNAME = "geni"; }
use GeniCredential;
use GeniCertificate;
use GeniAuthority;
use GeniHRN;
use GeniResponse;
use GeniUser;
use GeniRegistry;
# Configure ...
my $TB = "@prefix@";
my $SACERT = "$TB/etc/genisa.pem";
#
# This script can be used grab a CH credential and dump it to stdout.
# The context is the SA (the CH is granting a credential to the SA).
#
sub usage()
{
print STDERR "Usage: $0\n";
exit(-1);
}
sub fatal($)
{
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
usage()
if (@ARGV);
#
# Load the cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile($SACERT);
if (!defined($certificate)) {
fatal("Could not load certificate from $SACERT\n");
}
Genixmlrpc->SetContext(Genixmlrpc->Context($certificate));
my $clrcredential = GeniRegistry::ClearingHouse->GetCredential();
if (!defined($clrcredential)) {
fatal("Could not get clearinghouse credential\n");
}
print $clrcredential->asString();
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2009 University of Utah and the Flux Group.
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -237,6 +237,17 @@ if ($root->nodeName eq "credential") {
#print $root->toString(1) . "\n";
}
else {
#
# Must be consistent about namespaces or else the signature does
# not verify later.
#
$root->setNamespace($GeniUtil::XSI_NS, "xsi", 0);
$root->setAttributeNS($GeniUtil::XSI_NS, "noNamespaceSchemaLocation"
, $GeniUtil::CREDENTIAL_SCHEMA_LOCATION);
$root->setAttributeNS($GeniUtil::XSI_NS, "schemaLocation"
, $GeniUtil::EXTENSIONS_NS . " "
. $GeniUtil::EXTENSIONS_SCHEMA_LOCATION);
($credentials_node) = $root->getElementsByTagName("credential");
($signatures_node) = $root->getElementsByTagName("signatures");
......
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